<?php

/**
 * This file is part of the Codizer package.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @copyright   Copyright (c) 2010 Advisa (http://www.advisa.fr)
 * @author      Codizer Core Team <team@codizer.org>
 * @package     Codizer
 */

class f_xml_Xpath extends DOMXpath
{
	private static $instances;
	
	private $xmlfile;

	/**
	 * @var f_xml_XmlElement
	 */
	private $xmlobject;
	
	/**
	 * @return f_xml_Xpath
	 */
	public function __construct($xmlFile = null, $useDTD = false)
	{
		if(!is_null($xmlFile))
		{
			$this->xmlfile = realpath($xmlFile);

            if($useDTD == true)
            {
                $this->xmlobject = simplexml_load_file($this->xmlfile, "f_xml_XmlElement",  LIBXML_DTDVALID);
            }
            else
            {
                $this->xmlobject = simplexml_load_file($this->xmlfile, "f_xml_XmlElement",  LIBXML_NOCDATA);
            }
		}
	}
	
	/**
	 * Get multiton instance
	 *
	 * @return f_xml_Xpath
	 */
	public static function getInstance($xmlFile = null, $useDTD = false)
	{
		if(is_null($xmlFile))
		{
			return new self();
		}
		
		if(!isset(self::$instances[$xmlFile]))
		{
			if(is_file($xmlFile))
			{
				self::$instances[$xmlFile] = new self($xmlFile, $useDTD);
			}
			else
			{
				throw new Exception("XML file ".$xmlFile." not found");
			}			
		}
		
		return self::$instances[$xmlFile];
	}
		
	/**
	 * Set the xml string to parse
	 * 
	 * @param $xmlString
	 * @return f_xml_Xpath
	 */
	public function fromString($xmlString)
	{
		if(!is_null($xmlString) && is_string($xmlString))
		{
			$this->xmlfile = null;
			
			$this->xmlobject = simplexml_load_string($xmlString, "f_xml_XmlElement", LIBXML_NOCDATA);
		}	
		
		return $this;		
	}
	
	/**
	 * Set the xpath to get elements from
	 * 
	 * @example fromXpath("tag1/tag2")
	 *
	 * @param string $path
	 * @return f_xml_Xpath
	 */
	public function fromXpath($path)
	{
		$this->elements = $this->xmlobject->xpath($path);
		return $this;
	}

    public function asXml()
    {
        $result = '';
        foreach($this->elements as $element)
        {
            $result .= $element->asXml();
        }
        return $result;
    }

	/**
	 * Alias of fromXpath($path)->getElement()
	 *
	 * @param string $path
	 * @return array <f_xml_XmlElement>
	 */
	public function getElementFromXpath($path)
	{
		return $this->fromXpath($path)->getElement();
	}

	/**
	 * Alias of fromXpath($path)->getElements()
	 *
	 * @param string $path
	 * @return array <f_xml_XmlElement>
	 */
	public function getElementsFromXpath($path)
	{
		return $this->fromXpath($path)->getElements();
	}
	
	/**
	 * Alias of fromXpath($path)->getElement()
	 *
	 * @param string $path
	 * @return mixed
	 */
	public function getElementValueFromXpath($path)
	{
		$elements = $this->fromXpath($path)->getElements();
        if(isset($elements[0]) && is_object($elements[0]))
        {
            return $elements[0]->getContent();
        }
        return null;
	}
		
	/**
	 * Get unique or first element from given xpath
	 *
	 * @return f_xml_XmlElement
	 */
	public function getElement()
	{
		if(isset($this->elements) && count($this->elements) >= 1)
		{
			return $this->elements[0];
		}
		else
		{
			return null;
		}
	}
	
	/**
	 * Get all elements from the given xpath
	 *
	 * @return array<f_xml_XmlElement>
	 */
	public function getElements()
	{
		return $this->elements;
	}	
	
	/**
	 * Get attributes from the given xpath
	 *
	 * @return array <string>
	 */
	public function getAttributes()
	{
		if(is_null($this->getElement()))
		{
			return $this->xmlobject->getAttributes();
		}
		return $this->getElement()->getAttributes();
	}
	
	/**
	 * Get attribute value from the given xpath
	 *
	 * @param string $attributeName
	 * @param mixed $defaultValue
	 * @return string
	 */
	public function getAttributeValue($attributeName, $defaultValue = null)
	{
		if(is_null($this->getElement()))
		{
			return $this->xmlobject->getAttributeValue($attributeName, $defaultValue);
		}
		return $this->getElement()->getAttributeValue($attributeName, $defaultValue);
	}
	
	/**
	 * Return the path to the xmlfile
	 * 
	 * @return string
	 */
	public function getXmlFilePath()
	{
		return $this->xmlfile;
	}
}